extension ListExt<T> on List<T> {
  /// Returns the first element that satisfies the given predicate [test] or
  /// null if no element satisfies the predicate.
  T? firstWhereOrNull(bool Function(T element) test) {
    for (final element in this) {
      if (test(element)) {
        return element;
      }
    }
    return null;
  }

  /// Returns the last element that satisfies the given predicate [test] or
  /// null if no element satisfies the predicate.
  T? lastWhereOrNull(bool Function(T element) test) {
    for (var i = length - 1; i >= 0; i--) {
      final element = this[i];
      if (test(element)) {
        return element;
      }
    }
    return null;
  }

  /// join elements
  List<T> joinElements(T element) {
    final List<T> result = [];
    final last = length - 1;
    for (var i = 0; i < length; i++) {
      result.add(this[i]);
      if (i != last) {
        result.add(element);
      }
    }
    return result;
  }

  /// 如果此列表包含给定的 [other] 列表，则返回 true。
  ///
  /// 列表被认为是相等的，如果它们具有相同的长度，并且对应的位置上的元素是相等的。
  bool equals(List<T>? other) {
    if (other == null) {
      return false;
    }
    if (identical(this, other)) {
      return true;
    }
    if (length != other.length) {
      return false;
    }

    for (var i = 0; i < length; i++) {
      if (this[i] != other[i]) {
        return false;
      }
    }
    return true;
  }

  /// [elementAtOrNull] 的别名
  T? at(int index) => elementAtOrNull(index);

  /// 返回一个新的数组对象
  ///
  /// 与 js 中的 Array.prototype.slice() 方法类似
  ///
  /// 提取起始处的索引（从 0 开始）。
  /// 如果索引是负数，则从数组末尾开始计算——如果 start < 0，则使用 start + array.length。
  /// 如果 start < -array.length，则使用 0。
  /// 如果 start >= array.length，则不提取任何元素。
  /// [end] 可选
  /// 提取终止处的索引（从 0 开始）。slice() 会提取到但不包括 end 的位置。
  /// 如果索引是负数，则从数组末尾开始计算——如果 end < 0，则使用 end + array.length。
  /// 如果 end < -array.length，则使用 0。
  /// 如果 end >= array.length 或者省略了 end，则使用 array.length，提取所有元素直到末尾。
  /// 如果 end 在规范化后小于或等于 start，则不提取任何元素。
  List<T> slice(int start, [int? end]) {
    final List<T> result = [];
    if (isEmpty) {
      return result;
    }
    if (start < 0) {
      start += length;
    }
    if (start < 0) {
      start = 0;
    }
    if (end == null) {
      end = length;
    } else if (end < 0) {
      end += length;
    }
    if (end > length) {
      end = length;
    }
    if (end <= start) {
      return result;
    }
    return sublist(start, end);
  }
}
